/****************************************************************************
 * Copyright (C) 2025 Chenyz. All rights reserved.
 *
 * @file    TinyOS_CpuTicks.c
 *
 * @par     dependencies
 *          - ARMCM3.h (Cortex-M3 core peripherals)
 *          - TinyOS_CpuTicks.h (CPU tick counter functionality)
 *          - TinyOS_Task.h (Task management definitions)
 *          - TinyOS_Delay.h (Delay functionality)
 *          - TinyOS_Objects.h (Core data structures)
 *          - TinyOS_Event.h (Event management definitions)
 *          - TinyOS_Timer.h (Timer management definitions)
 *
 * @author  Chenyz
 *
 * @brief   CPU usage monitoring and system tick management for TinyOS with features:
 *          - Real-time CPU utilization calculation and reporting
 *          - Idle task based usage measurement methodology
 *          - Systick timer configuration and interrupt handling
 *          - Task delay expiration and wake-up management
 *          - Round-robin time slicing for same-priority tasks
 *          - Priority-based preemptive scheduling
 *          - Critical section protection for system management
 *          - Cortex-M3 specific hardware abstraction
 *
 * @version V1.0
 * @date    2025-09-16
 *
 * @note    Coding standard:
 *          - 4 spaces per indent level
 *          - Follow MISRA-C 2012 guidelines
 *          - Compiler compatibility: C99 and above
 *          - Cortex-M3 specific implementation
 *
 ****************************************************************************/

#include "stm32f10x.h"
#include "TinyOS_CpuTicks.h"
#include "TinyOS_Task.h"
#include "TinyOS_Delay.h"
#include "TinyOS_Event.h"
#include "TinyOS_Timer.h"
#include "TinyOS_Hook.h"

/* Global CPU usage monitoring variables */
static float CpuUsage;                    /* Current CPU usage percentage */
static uint32_t EnableCpuUsageState = 0;  /* CPU usage monitoring enable flag */
static uint32_t SysTickCount = 0;         /* System tick counter */
static uint32_t IdleTaskRunningCount = 0; /* Idle task execution counter */
static uint32_t IdleTaskRunningCountMax = 0; /* Maximum idle count for calibration */

# if TINYOS_ENABLE_CPUUSAGE == 1

/**
 * @brief Retrieves the current CPU usage percentage
 * 
 * This function returns the most recently calculated CPU utilization percentage.
 * The value represents the percentage of time the CPU is executing non-idle tasks.
 * 
 * @return float Current CPU usage percentage (0.0 - 100.0)
 */
float TinyOS_CpuUsageGet(void)
{
	float Usage = 0;
    uint32_t Status = TinyOS_TaskEnterCritical();	
	Usage = CpuUsage;
	TinyOS_TaskExitCritical(Status);   

	return Usage;
}

/**
 * @brief Calculates and updates CPU usage statistics
 * 
 * This function is called periodically to compute CPU utilization based on
 * idle task execution frequency. It performs calibration and periodic updates
 * to maintain accurate usage measurements.
 */
void TinyOS_CheckCpuUsage(void)
{
	/* Initialize monitoring on first call */
	if(EnableCpuUsageState == 0)
	{
		EnableCpuUsageState = 1;
		SysTickCount = 0;
		return;
	}
	
	/* Perform calibration after one second of operation */
	if(SysTickCount == TINYOS_TICKS_PER_SECOND)
	{
		IdleTaskRunningCountMax = IdleTaskRunningCount;
		IdleTaskRunningCount = 0;
		
		/* Re-enable scheduler after calibration period */
		TinyOS_TaskSchedulerLockDisable();
	}
	/* Update CPU usage percentage every second after calibration */
	else if(SysTickCount % TINYOS_TICKS_PER_SECOND == 0)
	{
		/* Calculate usage: 100% - (idle_time / total_time * 100%) */
		CpuUsage = 100.0 - ((float)IdleTaskRunningCount * 100.0 / (float)IdleTaskRunningCountMax);
		IdleTaskRunningCount = 0;
	}
}

/**
 * @brief Initializes CPU usage monitoring subsystem
 * 
 * This function resets all CPU usage monitoring variables to their initial state.
 * Should be called during system initialization before starting the scheduler.
 */
void TinyOS_InitCpuUsageState(void)
{
	IdleTaskRunningCount = 0;
	IdleTaskRunningCountMax = 0;
	CpuUsage = 0.0F;
	EnableCpuUsageState = 0;
}

/**
 * @brief Synchronizes with system tick for CPU usage monitoring
 * 
 * This function blocks until CPU usage monitoring has been properly initialized
 * and calibrated. Ensures accurate usage measurements by waiting for the
 * monitoring system to be ready.
 */
void TinyOS_CpuUsageSyncWithSystick(void)
{
	while(EnableCpuUsageState == 0);
}

#endif

/**
 * @brief Initializes the system tick counter
 * 
 * This function resets the system tick counter to zero. Used during system
 * initialization and for timing-related operations.
 */
void TinyOS_TickCountInit(void)
{
	SysTickCount = 0;
}

/**
 * @brief SysTick interrupt handler
 * 
 * This is the interrupt service routine for the SysTick timer.
 * It delegates to the task system tick handler for comprehensive
 * system timing management.
 */
void SysTick_Handler(void)
{
    TinyOS_TaskSystickHandler();
}

/**
 * @brief System tick interrupt handler for comprehensive timing management
 * 
 * This function processes periodic timer interrupts to manage:
 * - Task delay expiration and wake-up mechanisms
 * - Event wait timeouts for blocked tasks  
 * - Round-robin time slice management
 * - CPU usage monitoring and statistics collection
 * - Timer interrupt notifications
 * - Preemptive task scheduling decisions
 * 
 * The function executes within a critical section to ensure data consistency
 * across all system management operations.
 */
void TinyOS_TaskSystickHandler(void)
{
    TinyOS_NodeType* NodeCursor;
    TinyOS_TaskType* TempTaskHandler;   
    
    /* Enter critical section - protect shared system data structures */
    uint32_t Status = TinyOS_TaskEnterCritical();

    /* Process all tasks in the delay queue for expiration checks */
    for(
        NodeCursor = TaskDelayList.HeadNode.NextNode; 
        NodeCursor != &(TaskDelayList.HeadNode); 
        NodeCursor = NodeCursor->NextNode
    )
    {
        /* Convert list node to task control block */
        TempTaskHandler = TINYOS_NODE_PARENT(NodeCursor, TinyOS_TaskType, TaskDelayListNode);
        
        /* Decrement remaining delay ticks */
        TempTaskHandler->TaskDelayTicks--;
        
        /* Check if task's delay period has completed */
        if(TempTaskHandler->TaskDelayTicks == 0)
        {
            /* Handle event wait timeout if task was blocked on an event */
            if(TempTaskHandler->TaskEventBlock)
            {
                TinyOS_EventRemoveTask(TempTaskHandler, (void*)0, TinyOS_ErrorType_Timeout);
            }
                            
            /* Remove from delay list and mark as schedulable */
            TinyOS_TaskDelayTimeWake(TempTaskHandler);
            TinyOS_TaskSchedulerReady(TempTaskHandler);
        }
    }
    
    /* Manage round-robin time slicing for current task */
    CurrentTask->TaskSlice--;
    
    /* Check if current task has exhausted its time quantum */
    if(CurrentTask->TaskSlice == 0)
    {
        /* Only rotate tasks if multiple exist at same priority level */
        if(TinyOS_ListNodeCount(&TaskList[CurrentTask->TaskPrioity]) > 0)
        {
            /* Move current task to end of priority queue for fair scheduling */
            TinyOS_ListHeadDelete(&TaskList[CurrentTask->TaskPrioity]);
            TinyOS_ListTailInsert(&TaskList[CurrentTask->TaskPrioity], &CurrentTask->TaskListNode);
            
            /* Replenish time slice allowance */
            CurrentTask->TaskSlice = TINYOS_TASK_SLICE_MAX;
        }
    }
	
	/* Update system timing and CPU usage statistics */
	SysTickCount++;
	
# if TINYOS_ENABLE_CPUUSAGE == 1
	TinyOS_CheckCpuUsage();
#endif
	
	/* Exit critical section - restore interrupt state */
    TinyOS_TaskExitCritical(Status);
	
    /* Notify timer subsystem for extended timing services */
#if	TINYOS_ENABLE_TIMER == 1
    TinyOS_TimerNotifyFromInt();
#endif  

#if	TINYOS_ENABLE_HOOK == 1
    TinyOS_HookSystick();
#endif     
    /* Invoke scheduler to evaluate potential task switches */
    TinyOS_TaskScheduler();
}

/**
 * @brief Configures the SysTick timer for periodic interrupts
 * 
 * This function sets up the SysTick timer to generate periodic interrupts
 * at the specified millisecond interval, which drives the entire system
 * timing infrastructure including task scheduling and CPU usage monitoring.
 * 
 * @param ms The interval in milliseconds between SysTick interrupts
 * 
 * @note The SysTick interrupt priority is set to the lowest level to ensure
 *       that other interrupts can preempt it when necessary for system
 *       responsiveness.
 */
void TinyOS_SetSystickPeriod(uint32_t ms)
{
    /* Calculate reload value based on system clock frequency */
    SysTick->LOAD = ms * SystemCoreClock / 1000 - 1;
    
    /* Set SysTick interrupt to lowest priority */
    NVIC_SetPriority(SysTick_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
    
    /* Clear current value to start counting from zero */
    SysTick->VAL = 0;
    
    /* Configure and enable SysTick:
       - Use processor clock (not external reference)
       - Enable SysTick exception (interrupt generation)
       - Enable counter */
    SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | 
                    SysTick_CTRL_TICKINT_Msk |
                    SysTick_CTRL_ENABLE_Msk;    
}

